package restless.core {
	
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.geom.Matrix;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import restless.core.interfaces.I2d;
	import restless.core.interfaces.IUR;
	import restless.core.gameObjs.RLEManagedObj;
	import flash.display.StageQuality;
	import restless.utilities.Benchmark;
	import restless.utilities.display.RLEMatrixTransformer;
	import flash.events.MouseEvent;
	
	/**
	 * 
	 * @author Jordan Laine
	 * 
	 */
	
	public class RLEScreen extends RLEManagedObj {
		protected var camera:RLECamera;
		protected var cameraRect:Rectangle;
		protected var parallax:RLEParallax;
		
		protected var aRenderList:Array = [];
		protected var aBKG:Array = [];
		protected var aOverlay:Array = [];
		
		protected var bkgColor:uint;
		protected var matrix:Matrix;
		protected var tempObj:I2d;
		protected var tempObjRect:Rectangle;
		protected var bScaleForCamera:Boolean;
		protected var bFocus:Boolean;
		private var flashMouse:Point;
		private var _screenMouse:Point = new Point;
		private var cameraScale:Point = new Point;
		private var tempLayerNum:int;
		private var tempLayer:Array;
		
		public function RLEScreen(x:Number, y:Number, width:Number, height:Number) {
			setRE();
			setRect(x, y, width, height);
			bkgColor = RE.bkgColor;
			bitmapData = new BitmapData(rect.width, rect.height, true, 0x00000000);
			bitmap = new Bitmap;
			mark = new Benchmark;
			mouseOver = true;
		}
		
		public function changeCamera(camera:RLECamera):void {
			this.camera = camera;
			cameraRect = camera.rect;
		}
		
		public function getCameraRect():Rectangle {
			return cameraRect;
		}
		
		public function getFocus():Boolean {
			return bFocus;
		}
		
		public function setFocus(bool:Boolean):void {
			bFocus = bool;
		}
		
		public function addBKGing(obj:I2d):void {
			tempObj = obj;
			tempLayerNum = tempObj.layer;
			if (aBKG[tempLayerNum] == undefined) {
				aBKG[tempLayerNum] = [];
			}
			tempLayer = aBKG[tempLayerNum];
			tempLayer.push(tempObj);
			tempObj = null;
		}
		
		public function removeBKGing(obj:I2d):void {
			tempObj = obj;
			tempLayerNum = tempObj.layer;
			tempLayer = aBKG[tempLayerNum];
			var index:int = tempLayer.indexOf(tempObj);
			
			if (index > -1) {
				tempLayer.splice(index, 1);
			}
			tempObj = null;
		}
		
		public function addOverlaying(obj:I2d):void {
			tempObj = obj;
			tempLayerNum = tempObj.layer;
			if (aOverlay[tempLayerNum] == undefined) {
				aOverlay[tempLayerNum] = [];
			}
			var tempLayer:Array = aOverlay[tempLayerNum];
			tempLayer.push(tempObj);
			tempObj = null;
		}
		
		public function removeOverlaying(obj:I2d):void {
			tempObj = obj;
			tempLayerNum = tempObj.layer;
			tempLayer = aOverlay[tempLayerNum];
			var index:int = tempLayer.indexOf(tempObj);
			
			if (index > -1) {
				tempLayer.splice(index, 1);
			}
			tempObj = null;
		}
		
		public function setParallax(para:RLEParallax):void {
			if ( parallax == para ) { return; } 
			parallax = para;
			camera.parallax = parallax;
		}
		
		override public function mOver():void {
			cameraScale.x = camera.scaleX;
			cameraScale.y = camera.scaleY;
			if (!bScaleForCamera) { 
				_screenMouse.x = flashMouse.x + camera.x;
				_screenMouse.y = flashMouse.y + camera.y;
			} else {
				_screenMouse.x = flashMouse.x / cameraScale.x + camera.x;
				_screenMouse.y = flashMouse.y / cameraScale.y + camera.y;
			}
		}
		
		override public function hitTestPoint(point:Point):Boolean {
			flashMouse = point;
			tempBool = super.hitTestPoint(flashMouse);
			return tempBool;
		}
		
		public function get screenMouse():Point {
			return _screenMouse;
		}
		
		override public function mMove(mouse:Point):void {
			flashMouse = mouse;
		}
		
		public function getCamera():RLECamera {
			return camera;
		}
		
		public function clearOverlay():void {
			aOverlay.length = 0;
		}
		
		override public function render():void {
			var j:int;
			camera.render();
			cameraRect = camera.rect;
			aRenderList = camera.renderLayers;
			parallax = camera.parallax;
			
			bitmapData.lock();
			bitmapData.fillRect(rect, 0x00000000);
			
			var numOfObjs:int = aBKG.length - 1;
			for (i = 0; i <= numOfObjs; i++) {
				if (aBKG[i] != undefined) {
					j = aBKG[i].length - 1;
					for (j; j > -1; j--) {
						tempObj = aBKG[i][j];
						if (tempObj.visible) {
							tempObj.render();
							tempPoint.x = tempObj.x + this.x;
							tempPoint.y = tempObj.y + this.y;
							tempBitmapData = tempObj.bitmapData;
							tempRect = tempObj.renderRect;
							bitmapData.copyPixels( tempBitmapData, tempRect, tempPoint, null, null, true );	
						}
					}
				}
			}
			
			// Background Parallax rendering
			if (parallax != null) {
				tempBitmapData = parallax.getBkgBitmapData();
				if (tempBitmapData != null) {
					tempPoint.x = x;
					tempPoint.y = y;
					tempRect = rect;
					bitmapData.copyPixels( tempBitmapData, tempBitmapData.rect, tempPoint, null, null, true );
				}
			}
			
			// GameObjects rendering via 2D array
			numOfObjs = aRenderList.length - 1;
			for (i = 0; i <= numOfObjs; i++) {
				if (aRenderList[i] != undefined) {
					j = aRenderList[i].length - 1;
					for (j; j > -1; j--) {
						tempObj = aRenderList[i][j];
						if (tempObj.visible) {
							tempObj.render();
							tempBitmapData = tempObj.bitmapData;
							tempPoint.x = tempObj.x - cameraRect.x + this.x;
							tempPoint.y = tempObj.y - cameraRect.y + this.y;
							
							tempRect = tempObj.renderRect;
							bitmapData.copyPixels( tempBitmapData, tempRect, tempPoint, tempBitmapData, null, true);
						}
					}
				}
			}
			//trace("Render Time " + ( mark.stopNum() / numOfObjs ));
			// Forground Paralax rendering
			if (parallax != null) {
				tempBitmapData = parallax.getForBitmapData();
				if (tempBitmapData != null) {
					tempPoint.x = x;
					tempPoint.y = y;
					tempRect = rect;
					bitmapData.copyPixels( tempBitmapData, tempBitmapData.rect, tempPoint, null, null, true );
				}
			}
			
			// HUD and like items
			numOfObjs = aOverlay.length - 1;
			for (i = 0; i <= numOfObjs; i++) {
				if (aOverlay[i] != undefined) {
					j = aOverlay[i].length - 1;
					for (j; j > -1; j--) {
						tempObj = aOverlay[i][j];
						if (tempObj.visible) { 
							tempObj.render();
							tempPoint.x = tempObj.x + this.x;
							tempPoint.y = tempObj.y + this.y;
							tempBitmapData = tempObj.bitmapData;
							tempRect = tempObj.renderRect;
							bitmapData.copyPixels( tempBitmapData, tempRect, tempPoint, null, null, true );
						}
					}
				}
			}
			
			bitmapData.unlock();
			
			cameraScale.x = camera.scaleX;
			cameraScale.y = camera.scaleY;
			
			if (cameraScale.x != 1 || cameraScale.y != 1) {
				bScaleForCamera = true;
			} else {
				bScaleForCamera = false;
			}
			
			if (bScaleForCamera) {
				matrix = RLEMatrixTransformer.createScaleMatrix(cameraScale.x, cameraScale.y);
				tempBitmapData = new BitmapData(width, height, true, 0x00000000);
				tempBitmapData.draw(bitmapData, matrix);
				bitmapData = tempBitmapData;	
			}
			
			tempObj = null;
		}
		
		override public function dispose():void {
			camera = null;
			cameraRect = null;
			parallax = null;
			aRenderList = null;
			aOverlay = null;
			aBKG = null;
			tempObj = null;
			tempObjRect = null;
			matrix = null;
			
			super.dispose();
		}
	}
}